<?php


namespace App\Service\Store;


use App\Dao\StoreDao;
use App\Dao\StoreGroupDao;
use App\Dao\StoreMenuDao;
use App\Service\Service;
use Hyperf\AsyncQueue\Driver\DriverFactory;
use Hyperf\Di\Annotation\Inject;

class RightsService extends Service
{

    /**
     * 后台管理组Dao
     * @Inject()
     * @var StoreGroupDao
     */
    public $store_group_dao;

    /**
     * 管理员Dao
     * @Inject()
     * @var StoreDao
     */
    public $store_dao;

    /**
     * 后台菜单Dao
     * @Inject()
     * @var StoreMenuDao
     */
    public $store_menu_dao;


    public $store_routes;

    public function __construct(DriverFactory $driverFactory)
    {
        parent::__construct($driverFactory);
        $this->store_routes = getHttpStoreRoutes();
    }


    /**
     * 用户搜索
     * @param array $params
     * @return mixed
     */
    public function userSearch(array $params)
    {
        $map = [];
        isset($params['start_time']) && !isset($params['end_time'])  && !empty($params['start_time']) && $map['created_at'] = ['>=', strtotime($params['start_time'])]; // 创建开始时间
        isset($params['end_time']) &&  !isset($params['start_time'])  && !empty($params['end_time']) && $map['created_at'] = ['<=', strtotime($params['end_time'])]; // 创建结束时间

        isset($params['end_time']) &&  isset($params['start_time']) &&
        !empty($params['end_time']) && !empty($params['start_time']) &&
        $map['between_field'] = ['created_at' =>[strtotime($params['start_time']), strtotime($params['end_time'])]]; // 有创建开始和结束时间

        isset($params['search']) && !empty($params['search']) // 搜索
        && $map['or_field'] = [
            'phone' => ['like', "%{$params['search']}%"], // 手机号码
            'name' => ['like', "%{$params['search']}%"], // 昵称/姓名
        ];

        $sort = 'created_at desc';
        $select = ['id', 'created_at', 'group_id', 'phone', 'name', 'sign', 'email', 'status'];
        $page_size = 20;

        $store_list = $this->store_dao->getStoresByMap($map, $sort, $select, $page_size)->toArray();

        $store_list['data'] = $this->joinStoreData($store_list['data']);

        return $store_list;
    }

    /**
     * 拼接后台用户数据
     * @param array $store_list
     * @return array
     */
    public function joinStoreData(array $store_list)
    {
        $group_ids = array_unique(array_column($store_list, 'group_id'));

        $group_names = $this->store_group_dao->getGroupsByIds($group_ids, ['id', 'group_name'])->pluck('group_name', 'id')->toArray();

        foreach ($store_list as &$item) {
            $item['create_time'] = date("Y.m.d H:i", (int)$item['created_at']); // 创建时间
            $item['group_name'] = $group_names[$item['group_id']]?? "无"; // 角色名称

        }

        return $store_list;
    }

    /**
     * 添加用户
     * @param array $params
     * @return mixed
     */
    public function userAdd(array $params)
    {
        $data = [];
        // 必填项
        $data['phone'] = $params['phone']; // 手机号
        $store = $this->store_dao->loginByPhone($params['phone']); // 手机号鉴定是否存在
        $store && $this->error("手机号已经存在");
        $data['login_pwd'] = password_hash($params['login_pwd'], PASSWORD_DEFAULT) ; // 登录密码
        $data['group_id'] = (int)$params['group_id']; // 角色ID
        $data['name'] = $params['name']; // 昵称/姓名

        // 选填项
        isset($params['avatar']) && !empty($params['avatar']) && $data['avatar'] = $params['avatar']; // 头像
        isset($params['sign']) && !empty($params['sign']) && $data['sign'] = $params['sign']; // 个性签名
        isset($params['email']) && !empty($params['email']) && $data['email'] = $params['email']; // 邮箱地址
        isset($params['birthday']) && !empty($params['birthday']) && $data['birthday'] = strtotime($params['birthday']); // 生日

        isset($params['sex']) && $data['sex'] = (int)$params['sex']; // 性别/0保密/1男/2女
        isset($params['status']) && $data['status'] = (int)$params['status']; // 账号状态/0禁用/1正常

        $result = $this->store_dao->create($data);
        !$result && $this->error("后台用户创建失败");
        return $result;
    }



    /**
     * 角色搜索
     * @param array $params
     * @return mixed
     */
    public function groupSearch(array $params)
    {
        $map = [];
        isset($params['start_time']) && !isset($params['end_time'])  && !empty($params['start_time']) && $map['created_at'] = ['>=', strtotime($params['start_time'])]; // 创建开始时间
        isset($params['end_time']) &&  !isset($params['start_time'])  && !empty($params['end_time']) && $map['created_at'] = ['<=', strtotime($params['end_time'])]; // 创建结束时间

        isset($params['end_time']) &&  isset($params['start_time']) &&
        !empty($params['end_time']) && !empty($params['start_time']) &&
        $map['between_field'] = ['created_at' =>[strtotime($params['start_time']), strtotime($params['end_time'])]]; // 有创建开始和结束时间

        isset($params['search']) && !empty($params['search']) // 搜索
        && $map['or_field'] = [
            'group_name' => ['like', "%{$params['search']}%"], // 用户组名称
            'description' => ['like', "%{$params['search']}%"], // 角色权限描述
        ];
        $sort = 'sort desc';
        $select = ['id', 'created_at', 'parent_id', 'group_name', 'auth_menus', 'auth_routes', 'description', 'sort', 'status', 'is_super', 'is_login'];
        $page_size = 20;

        $group_list = $this->store_group_dao->getStoreGroupByMap($map, $sort, $select, $page_size)->toArray();

        $group_list['data'] = $this->joinGroupData($group_list['data']);

        return $group_list;
    }

    /**
     * 拼接组数据
     * @param array $group_list
     * @return array
     */
    public function joinGroupData(array $group_list)
    {
        $parent_ids = array_unique(array_column($group_list, 'parent_id'));
        $group_names = $this->store_group_dao->getGroupsByIds($parent_ids,['id', 'group_name'])->pluck('group_name', 'id')->toArray();

        foreach ($group_list as &$item) {
            $item['create_time'] = date("Y.m.d H:i", (int)$item['created_at']); // 创建时间
            $parent_name = null;
            if ($item['parent_id'] == 0) {
                $parent_name = "顶级角色";
            } else {
                $parent_name = $group_names[$item['parent_id']]??"无";
            }
            $item['parent_name'] = $parent_name; // 上级组名称

        }

        return $group_list;
    }


    /**
     * 后台用户组创建
     * @param array $params
     * @return mixed
     */
    public function groupAdd(array $params)
    {
        $data = [];

        // 必填项
        $name_group = $this->store_group_dao->getGroupByName($params['group_name']);
        $name_group && $this->error("存在相同名称的用户组");
        $data['group_name'] = $params['group_name']; // 用户组名称

        // 选填项
        isset($params['parent_id']) && !empty($params['parent_id']) && $data['parent_id'] = (int)$params['parent_id'];  // 上级用户组ID
        isset($params['auth_menus']) && !empty($params['auth_menus']) && $data['auth_menus'] = $params['auth_menus'];  // 选定菜单ID的数组
        isset($params['description']) && !empty($params['description']) && $data['description'] = $params['description'];  // 角色权限描述
        isset($params['sort']) && $data['sort'] = (int)$params['sort'];  // 排序
        isset($params['status']) &&  $data['status'] = (int)$params['status'];  // 角色状态 0-禁用 1-正常
        isset($params['is_super']) && $data['is_super'] = (int)$params['is_super'];  // 是否是超级管理员 0-否 1-是
        isset($params['is_login']) &&  $data['is_login'] = (int)$params['is_login'];  // 是否登录总后台 0-否 1-是

        $result = $this->store_group_dao->create($data);
        !$result && $this->error("创建用户组失败");
        return $result;
    }

    /**
     * 后台菜单添加
     * @param array $params
     * @return mixed
     */
    public function menuAdd(array $params)
    {
        $store_routes = $this->store_routes;

        $data = [];
        // 必填项

        $first = $this->store_menu_dao->getMenuByName($params['menu_name']);
        $first && $first->parent_id == $params['parent_id'] && $this->error("同一个上级菜单已有相同本级名称的菜单");
        $data['menu_name'] = $params['menu_name']; // 菜单名称

        if ($params['parent_id'] == 0) {
            $data['level'] = 1; // 第一级菜单 当前层级，最上层为1的 第1级菜单
        } else {
            $parent_menu = $this->store_menu_dao->getMenuById($params['parent_id']);
            !$parent_menu && $this->error("不存在的上级菜单");
            $data['level'] = $parent_menu->level + 1;
            $data['level'] > $this->store_menu_dao::MAX_LEVEL && $this->error("最高层级不能超过".$this->store_menu_dao::MAX_LEVEL."层");
        }
        $data['parent_id'] = (int)$params['parent_id']; // 上级菜单

        // 选填项
        if ( isset($params['auth_routes']) && !empty($params['auth_routes']) ) { // 前端菜单对应绑定的后端路由
            !is_array($params['auth_routes']) && $this->error("请传递路由数组");
            $routes = $params['auth_routes'];

            foreach ($routes as $route) {
                if (!in_array($route, $store_routes)) {
                    $this->error("存在无效的路由");
                }
            }
            $data['auth_routes'] = $routes;
        }

        isset($params['menu_uri']) && !empty($params['menu_uri']) && $data['menu_uri'] = $params['menu_uri']; // 菜单uri路径
        isset($params['icon']) && !empty($params['icon']) && $data['icon'] = $params['icon']; // 图标在前端的路径
        isset($params['sort']) && $data['sort'] = (int)$params['sort']; // 排序
        isset($params['system_menu']) && $data['system_menu'] = (int)$params['system_menu']; // 是否为系统菜单，系统菜单不可删除 0-否 1-是
        isset($params['super_menu']) && $data['super_menu'] = (int)$params['super_menu']; // 是否为超级管理员才能看到的菜单 0-否 1-是
        isset($params['leaf']) && $data['leaf'] = (int)$params['leaf']; // 是否只有一个节点 0-否 1-是

        $result = $this->store_menu_dao->create($data);
        !$result && $this->error("创建菜单失败");
        return $result;
    }

    /**
     * 用户信息修改
     * @param int $id
     * @param array $params
     * @return mixed
     */
    public function userPolish(int $id, array $params)
    {
        $store = $this->store_dao->first($id, false);
        !$store && $this->error("该后台用户不存在");

       if( isset($params['phone']) && !empty($params['phone']) )
       {
           if ($store->phone != $params['phone']) {
               $phone_store = $this->store_dao->loginByPhone($params['phone']);
               $phone_store && $this->error("该手机号已使用过");
           }
           $store->phone = $params['phone']; // 手机号
       }

        isset($params['login_pwd']) && !empty($params['login_pwd']) && $store->login_pwd = password_hash($params['login_pwd'], PASSWORD_DEFAULT) ; // 登录密码

        if ( isset($params['group_id']) && !empty($params['group_id']) ){
            $group = $this->store_group_dao->getGroupById((int)$params['group_id']);
            !$group && $this->error("该用户组不存在");
            $store->group_id = (int)$params['group_id']; // 角色ID
        }

        isset($params['name']) && !empty($params['name']) && $store->name = $params['name']; // 手机号
        isset($params['avatar']) && !empty($params['avatar']) && $store->avatar = $params['avatar']; // 头像
        isset($params['sign']) && !empty($params['sign']) && $store->sign = $params['sign']; // 个性签名
        isset($params['email']) && !empty($params['email']) && $store->email = $params['email']; // 邮箱地址
        isset($params['birthday']) && !empty($params['birthday']) && $store->birthday = strtotime($params['birthday']); // 生日
        isset($params['sex']) && $store->sex = (int)$params['sex']; // 性别/0保密/1男/2女
        isset($params['status']) && $store->status = (int)$params['status']; // 账号状态/0禁用/1正常

        $result = $store->save();
        !$result && $this->error("修改失败");
        return $result;
    }

    /**
     * 菜单绑定路由
     * @param int $id
     * @param string $route
     */
    public function menuRouteBind(int $id, string $route)
    {
        $store_routes = $this->store_routes;
        !in_array($route, $store_routes) && $this->error("不属于后台的后端路由里面");

        $menu = $this->store_menu_dao->getMenuById($id);
        !$menu && $this->error("该菜单不存在");

        $type = (int)$this->request->input('type');

        switch ($type) {
            case 1:
                if (empty($menu->auth_routes)) {
                    $menu->auth_routes = [$route];
                } else {
                    in_array($route, $menu->auth_routes) && $this->error("该路由已经绑定了该菜单");
                    $auth_routes = $menu->auth_routes;
                    array_push($auth_routes, $route);
                    $menu->auth_routes = $auth_routes;
                }
                break;
            case 2:
                if (!empty($menu->auth_routes)) {
                    $auth_routes = $menu->auth_routes;
                    $index =  array_search($route, $auth_routes);
                    $index === false && $this->error("该菜单未绑定该路由");
                    unset($auth_routes[$index]);
                    $menu->auth_routes = array_values($auth_routes);
                } else {
                    $this->error("没有路由");
                }
                break;
            default:
                $this->error("请选择1或者2");
                break;
        }

        $result = $menu->save();
        !$result && $this->error("保存路由失败");
        $this->success($result);
    }

    /**
     * 菜单信息修改
     *
     * @param int $id 菜单ID
     * @param array $params
     * @return mixed
     */
    public function menuPolishAndMultiBind(int $id, array $params)
    {
        $store_routes = $this->store_routes;

        $menu = $this->store_menu_dao->getMenuById($id);
        !$menu && $this->error("该菜单不存在");

        if (isset($params['auth_routes'])) {
            !is_array($params['auth_routes']) && $this->error("请传递路由数组");
            $routes = $params['auth_routes'];

            foreach ($routes as $route) {
                if (!in_array($route, $store_routes)) {
                    $this->error("存在无效的路由");
                }

            }
            $menu->auth_routes = $routes;

        }

        if (isset($params['parent_id'])) { // 上级菜单ID
            if ($params['parent_id'] == 0) {
                $menu->level = 1; // 第一级菜单 当前层级，最上层为1的 第1级菜单
            } else {
                $parent_menu = $this->store_menu_dao->getMenuById($params['parent_id']);
                !$parent_menu && $this->error("不存在的上级菜单");
                $menu->level = $parent_menu->level + 1;
                $menu->level > $this->store_menu_dao::MAX_LEVEL && $this->error("最高层级不能超过".$this->store_menu_dao::MAX_LEVEL."层");
            }
            $menu->parent_id = (int)$params['parent_id']; // 上级菜单
        }

        if (isset($params['menu_name'])) { // 菜单名称
            if ($menu->menu_name != $params['menu_name']) {
                $first = $this->store_menu_dao->getMenuByName($params['menu_name']);
                if ($first) {
                    if (!isset($params['parent_id'])) {
                        $first->parent_id == $menu->parent_id && $this->error("同一个上级菜单已有相同本级名称的菜单");
                    } else {
                        $first->parent_id == $params['parent_id'] && $this->error("同一个上级菜单已有相同本级名称的菜单");
                    }

                }

            }
            $menu->menu_name = $params['menu_name'];
        }

        isset($params['menu_uri']) && !empty($params['menu_uri']) && $menu->menu_uri = $params['menu_uri']; // 菜单uri路径
        isset($params['icon']) && !empty($params['icon']) && $menu->icon = $params['icon']; // 图标在前端的路径

        isset($params['sort']) && $menu->sort = (int)$params['sort']; // 排序
        isset($params['system_menu']) && $menu->system_menu = (int)$params['system_menu']; // 是否为系统菜单，系统菜单不可删除 0-否 1-是
        isset($params['super_menu']) && $menu->super_menu = (int)$params['super_menu']; // 是否为超级管理员才能看到的菜单 0-否 1-是
        isset($params['leaf']) && $menu->leaf = (int)$params['leaf']; // 是否只有一个节点 0-否 1-是

        $result = $menu->save();
        !$result && $this->error("菜单信息修改失败");

        return $result;

    }

    /**
     * 获得菜单及所有下级
     * @return array
     */
    public function getMenus()
    {
        $menus = $this->store_menu_dao->getMenusByStartLevel()->toArray(); // 必须有 id, level, parent_id 存在
        $whole_menus = $this->menuTree($menus, 0,1, 1);
        return $whole_menus;
    }

    /**
     * 菜单循环树
     * @param mixed $menus
     * @param int $parent_id
     * @param int $start_level
     * @param int $current_level
     * @return array
     */
    public function menuTree($menus,int $parent_id ,int $start_level, int $current_level)
    {
        if ($current_level > $this->store_menu_dao::MAX_LEVEL)
            return []; // 超过限制了
        if (!isset($menus[$current_level][$parent_id])) return [];

        $current_menus = $menus[$current_level][$parent_id];// 当前层上级ID存在

        foreach ($current_menus as $key => $current_menu) {
            $children = $this->menuTree($menus, $current_menu['id'],$start_level, $current_level + 1);
            $current_menus[$key]['children'] = empty($children)?[]:$children;
        }

        return $current_menus;

    }


}